import Foundation
import UIKit
import Display
import ComponentFlow
import AnimatedTextComponent
import ActivityIndicator
import BundleIconComponent
import ShimmerEffect
import GlassBackgroundComponent

public final class ButtonBadgeComponent: Component {
    let fillColor: UIColor
    let style: ButtonTextContentComponent.BadgeStyle
    let content: AnyComponent<Empty>
    
    public init(
        fillColor: UIColor,
        style: ButtonTextContentComponent.BadgeStyle,
        content: AnyComponent<Empty>
    ) {
        self.fillColor = fillColor
        self.style = style
        self.content = content
    }
    
    public static func ==(lhs: ButtonBadgeComponent, rhs: ButtonBadgeComponent) -> Bool {
        if lhs.fillColor != rhs.fillColor {
            return false
        }
        if lhs.style != rhs.style {
            return false
        }
        if lhs.content != rhs.content {
            return false
        }
        return true
    }
    
    public final class View: UIView {
        private let backgroundView: UIImageView
        private let content = ComponentView<Empty>()
        
        private var component: ButtonBadgeComponent?
        
        override public init(frame: CGRect) {
            self.backgroundView = UIImageView()
            
            super.init(frame: frame)
            
            self.addSubview(self.backgroundView)
        }
        
        required public init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        public func update(component: ButtonBadgeComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
            let height: CGFloat
            switch component.style {
            case .round:
                height = 20.0
            case .roundedRectangle:
                height = 18.0
            }
            let contentInset: CGFloat = 10.0
            
            let themeUpdated = self.component?.fillColor != component.fillColor
            self.component = component
            
            let contentSize = self.content.update(
                transition: transition,
                component: component.content,
                environment: {},
                containerSize: availableSize
            )
            let backgroundWidth: CGFloat = max(height, contentSize.width + contentInset)
            let backgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: backgroundWidth, height: height))
            
            transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
            
            if let contentView = self.content.view {
                if contentView.superview == nil {
                    self.addSubview(contentView)
                }
                transition.setFrame(view: contentView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundFrame.width - contentSize.width) * 0.5), y: floorToScreenPixels((backgroundFrame.height - contentSize.height) * 0.5)), size: contentSize))
            }
            
            if themeUpdated || backgroundFrame.height != self.backgroundView.image?.size.height {
                switch component.style {
                case .round:
                    self.backgroundView.image = generateStretchableFilledCircleImage(diameter: backgroundFrame.height, color: component.fillColor)
                case .roundedRectangle:
                    self.backgroundView.image = generateFilledRoundedRectImage(size: CGSize(width: height, height: height), cornerRadius: 4.0, color: component.fillColor)?.stretchableImage(withLeftCapWidth: Int(height / 2.0), topCapHeight: Int(height / 2.0))
                }
            }
            
            return backgroundFrame.size
        }
    }
    
    public func makeView() -> View {
        return View(frame: CGRect())
    }
    
    public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
        return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
    }
}

public final class ButtonTextContentComponent: Component {
    public enum BadgeStyle {
        case round
        case roundedRectangle
    }
    
    public let text: String
    public let badge: Int
    public let textColor: UIColor
    public let fontSize: CGFloat
    public let badgeBackground: UIColor
    public let badgeForeground: UIColor
    public let badgeStyle: BadgeStyle
    public let badgeIconName: String?
    public let combinedAlignment: Bool
    
    public init(
        text: String,
        badge: Int,
        textColor: UIColor,
        fontSize: CGFloat = 17.0,
        badgeBackground: UIColor,
        badgeForeground: UIColor,
        badgeStyle: BadgeStyle = .round,
        badgeIconName: String? = nil,
        combinedAlignment: Bool = false
    ) {
        self.text = text
        self.badge = badge
        self.textColor = textColor
        self.fontSize = fontSize
        self.badgeBackground = badgeBackground
        self.badgeForeground = badgeForeground
        self.badgeStyle = badgeStyle
        self.badgeIconName = badgeIconName
        self.combinedAlignment = combinedAlignment
    }
    
    public static func ==(lhs: ButtonTextContentComponent, rhs: ButtonTextContentComponent) -> Bool {
        if lhs.text != rhs.text {
            return false
        }
        if lhs.badge != rhs.badge {
            return false
        }
        if lhs.textColor != rhs.textColor {
            return false
        }
        if lhs.fontSize != rhs.fontSize {
            return false
        }
        if lhs.badgeBackground != rhs.badgeBackground {
            return false
        }
        if lhs.badgeForeground != rhs.badgeForeground {
            return false
        }
        if lhs.badgeStyle != rhs.badgeStyle {
            return false
        }
        if lhs.badgeIconName != rhs.badgeIconName {
            return false
        }
        if lhs.combinedAlignment != rhs.combinedAlignment {
            return false
        }
        return true
    }

    public final class View: UIView {
        private var component: ButtonTextContentComponent?
        private weak var componentState: EmptyComponentState?

        private let content = ComponentView<Empty>()
        private var badge: ComponentView<Empty>?
        
        override init(frame: CGRect) {
            super.init(frame: frame)
        }

        required init(coder: NSCoder) {
            preconditionFailure()
        }
        
        override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            return super.hitTest(point, with: event)
        }

        func update(component: ButtonTextContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
            let previousBadge = self.component?.badge
            
            self.component = component
            self.componentState = state
            
            var badgeSpacing: CGFloat = 6.0
            if component.badgeIconName != nil {
                badgeSpacing += 4.0
            }
            
            let contentSize = self.content.update(
                transition: .immediate,
                component: AnyComponent(Text(
                    text: component.text,
                    font: Font.semibold(component.fontSize),
                    color: component.textColor
                )),
                environment: {},
                containerSize: availableSize
            )
            
            var badgeSize: CGSize?
            if component.badge > 0 {
                var badgeTransition = transition
                let badge: ComponentView<Empty>
                if let current = self.badge {
                    badge = current
                } else {
                    badgeTransition = .immediate
                    badge = ComponentView()
                    self.badge = badge
                }
                
                var badgeContent: [AnyComponentWithIdentity<Empty>] = []
                if let badgeIconName = component.badgeIconName {
                    badgeContent.append(AnyComponentWithIdentity(
                        id: "icon",
                        component: AnyComponent(BundleIconComponent(
                            name: badgeIconName,
                            tintColor: component.badgeForeground
                        )))
                    )
                }
                badgeContent.append(AnyComponentWithIdentity(
                    id: "text", 
                    component: AnyComponent(AnimatedTextComponent(
                        font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: .monospacedNumbers),
                        color: component.badgeForeground,
                        items: [
                            AnimatedTextComponent.Item(id: AnyHashable(0), content: .number(component.badge, minDigits: 0))
                        ]
                    )))
                )
                
                badgeSize = badge.update(
                    transition: badgeTransition,
                    component: AnyComponent(ButtonBadgeComponent(
                        fillColor: component.badgeBackground,
                        style: component.badgeStyle,
                        content: AnyComponent(HStack(badgeContent, spacing: 2.0))
                    )),
                    environment: {},
                    containerSize: CGSize(width: 100.0, height: 100.0)
                )
            }
            
            var size = contentSize
            var measurementSize = size
            if let badgeSize {
                if component.combinedAlignment {
                    measurementSize.width += badgeSpacing
                    measurementSize.width += badgeSize.width
                }
                size.height = max(size.height, badgeSize.height)
            }
            
            let contentFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - measurementSize.width) * 0.5), y: floorToScreenPixels((size.height - measurementSize.height) * 0.5)), size: measurementSize)
            
            if let contentView = self.content.view {
                if contentView.superview == nil {
                    self.addSubview(contentView)
                }
                transition.setFrame(view: contentView, frame: CGRect(origin: contentFrame.origin, size: contentSize))
            }
            
            if let badgeSize, let badge = self.badge {
                let badgeFrame = CGRect(origin: CGPoint(x: contentFrame.minX + contentSize.width + badgeSpacing, y: floorToScreenPixels((size.height - badgeSize.height) * 0.5) + 1.0), size: badgeSize)
                
                if let badgeView = badge.view {
                    var animateIn = false
                    if badgeView.superview == nil {
                        animateIn = true
                        self.addSubview(badgeView)
                    }
                    
                    if animateIn {
                        badgeView.frame = badgeFrame
                    } else {
                        transition.setFrame(view: badgeView, frame: badgeFrame)
                        
                        if !transition.animation.isImmediate, let previousBadge, previousBadge != component.badge {
                            let middleScale: CGFloat = previousBadge < component.badge ? 1.1 : 0.9
                            let values: [NSNumber] = [1.0, middleScale as NSNumber, 1.0]
                            badgeView.layer.animateKeyframes(values: values, duration: 0.25, keyPath: "transform.scale")
                        }
                    }
                    
                    if animateIn, !transition.animation.isImmediate {
                        badgeView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
                        badgeView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
                    }
                }
            } else {
                if let badge = self.badge {
                    self.badge = nil
                    if let badgeView = badge.view {
                        if !transition.animation.isImmediate {
                            badgeView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak badgeView] _ in
                                badgeView?.removeFromSuperview()
                            })
                            badgeView.layer.animateScale(from: 1.0, to: 0.001, duration: 0.25, removeOnCompletion: false)
                        } else {
                            badgeView.removeFromSuperview()
                        }
                    }
                }
            }
            
            return size
        }
    }

    public func makeView() -> View {
        return View(frame: CGRect())
    }

    public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
        return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
    }
}

public final class ButtonComponent: Component {
    public struct Background: Equatable {
        public enum Style {
            case glass
            case legacy
        }
        
        public var style: Style
        public var color: UIColor
        public var foreground: UIColor
        public var pressedColor: UIColor
        public var cornerRadius: CGFloat
        public var isShimmering: Bool

        public init(
            style: Style = .legacy,
            color: UIColor,
            foreground: UIColor,
            pressedColor: UIColor,
            cornerRadius: CGFloat = 10.0,
            isShimmering: Bool = false
        ) {
            self.style = style
            self.color = color
            self.foreground = foreground
            self.pressedColor = pressedColor
            self.cornerRadius = cornerRadius
            self.isShimmering = isShimmering
        }
        
        public func withIsShimmering(_ isShimmering: Bool) -> Background {
            return Background(
                style: self.style,
                color: self.color,
                foreground: self.foreground,
                pressedColor: self.pressedColor,
                cornerRadius: self.cornerRadius,
                isShimmering: isShimmering
            )
        }
    }

    public let background: Background
    public let content: AnyComponentWithIdentity<Empty>
    public let isEnabled: Bool
    public let tintWhenDisabled: Bool
    public let allowActionWhenDisabled: Bool
    public let displaysProgress: Bool
    public let action: () -> Void
    
    public init(
        background: Background,
        content: AnyComponentWithIdentity<Empty>,
        isEnabled: Bool = true,
        tintWhenDisabled: Bool = true,
        allowActionWhenDisabled: Bool = false,
        displaysProgress: Bool = false,
        action: @escaping () -> Void
    ) {
        self.background = background
        self.content = content
        self.isEnabled = isEnabled
        self.tintWhenDisabled = tintWhenDisabled
        self.allowActionWhenDisabled = allowActionWhenDisabled
        self.displaysProgress = displaysProgress
        self.action = action
    }

    public static func ==(lhs: ButtonComponent, rhs: ButtonComponent) -> Bool {
        if lhs.background != rhs.background {
            return false
        }
        if lhs.content != rhs.content {
            return false
        }
        if lhs.isEnabled != rhs.isEnabled {
            return false
        }
        if lhs.tintWhenDisabled != rhs.tintWhenDisabled {
            return false
        }
        if lhs.allowActionWhenDisabled != rhs.allowActionWhenDisabled {
            return false
        }
        if lhs.displaysProgress != rhs.displaysProgress {
            return false
        }
        return true
    }

    private final class ContentItem {
        let id: AnyHashable
        let view = ComponentView<Empty>()

        init(id: AnyHashable) {
            self.id = id
        }
    }

    public final class View: HighlightTrackingButton {
        private var component: ButtonComponent?
        private weak var componentState: EmptyComponentState?

        private var containerView: UIView
        private var shimmeringView: ButtonShimmeringView?
        private var chromeView: UIImageView?
        private var contentItem: ContentItem?
        
        private var activityIndicator: ActivityIndicator?
        
        override init(frame: CGRect) {
            self.containerView = UIView()
            self.containerView.clipsToBounds = true
            self.containerView.isUserInteractionEnabled = false
            
            super.init(frame: frame)
            
            self.addSubview(self.containerView)
            
            self.addTarget(self, action: #selector(self.pressed), for: .touchUpInside)
            
            self.highligthedChanged = { [weak self] highlighted in
                if let self, let component = self.component, component.isEnabled {
                    switch component.background.style {
                    case .glass:
                        let transition = ComponentTransition(animation: .curve(duration: highlighted ? 0.25 : 0.35, curve: .spring))
                        if highlighted {
                            let highlightedColor = component.background.color.withMultiplied(hue: 1.0, saturation: 0.77, brightness: 1.01)
                            transition.setBackgroundColor(view: self.containerView, color: highlightedColor)
                            transition.setScale(view: self.containerView, scale: 1.05)
                        } else {
                            transition.setBackgroundColor(view: self.containerView, color: component.background.color)
                            transition.setScale(view: self.containerView, scale: 1.0)
                        }
                    case .legacy:
                        if highlighted {
                            self.containerView.layer.removeAnimation(forKey: "opacity")
                            self.containerView.alpha = 0.7
                        } else {
                            self.containerView.alpha = 1.0
                            self.containerView.layer.animateAlpha(from: 0.7, to: 1.0, duration: 0.2)
                        }
                    }
                }
            }
        }

        required init(coder: NSCoder) {
            preconditionFailure()
        }
        
        @objc private func pressed() {
            guard let component = self.component else {
                return
            }
            component.action()
        }
        
        override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            return super.hitTest(point, with: event)
        }

        func update(component: ButtonComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
            self.component = component
            self.componentState = state
            
            self.isEnabled = (component.isEnabled || component.allowActionWhenDisabled) && !component.displaysProgress
            
            transition.setBackgroundColor(view: self.containerView, color: component.background.color)
            
            var cornerRadius: CGFloat = component.background.cornerRadius
            if case .glass = component.background.style, component.background.cornerRadius == 10.0 {
                cornerRadius = availableSize.height * 0.5
            }
            transition.setCornerRadius(layer: self.containerView.layer, cornerRadius: cornerRadius)
            
            var contentAlpha: CGFloat = 1.0
            if component.displaysProgress {
                contentAlpha = 0.0
            } else if !component.isEnabled && component.tintWhenDisabled {
                contentAlpha = 0.7
            }
 
            var previousContentItem: ContentItem?
            let contentItem: ContentItem
            var contentItemTransition = transition
            if let current = self.contentItem, current.id == component.content.id {
                contentItem = current
            } else {
                contentItemTransition = .immediate
                previousContentItem = self.contentItem
                contentItem = ContentItem(id: component.content.id)
                self.contentItem = contentItem
            }

            let contentSize = contentItem.view.update(
                transition: contentItemTransition,
                component: component.content.component,
                environment: {},
                containerSize: availableSize
            )
            if let contentView = contentItem.view.view {
                var animateIn = false
                var contentTransition = transition
                if contentView.superview == nil {
                    contentTransition = .immediate
                    animateIn = true
                    contentView.isUserInteractionEnabled = false
                    self.containerView.addSubview(contentView)
                    
                    contentItem.view.parentState = state
                }
                let contentFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) * 0.5), y: floorToScreenPixels((availableSize.height - contentSize.height) * 0.5)), size: contentSize)
                
                contentTransition.setFrame(view: contentView, frame: contentFrame)
                contentTransition.setAlpha(view: contentView, alpha: contentAlpha)
                
                if animateIn && previousContentItem != nil && !transition.animation.isImmediate {
                    contentView.layer.animateScale(from: 0.4, to: 1.0, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring)
                    contentView.layer.animateAlpha(from: 0.0, to: contentAlpha, duration: 0.1)
                    contentView.layer.animatePosition(from: CGPoint(x: 0.0, y: -availableSize.height * 0.15), to: CGPoint(), duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
                }
            }
            
            if let previousContentItem, let previousContentView = previousContentItem.view.view {
                if !transition.animation.isImmediate {
                    previousContentView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
                    previousContentView.layer.animateAlpha(from: contentAlpha, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak previousContentView] _ in
                        previousContentView?.removeFromSuperview()
                    })
                    previousContentView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: availableSize.height * 0.35), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
                } else {
                    previousContentView.removeFromSuperview()
                }
            }
            
            if component.displaysProgress {
                let activityIndicator: ActivityIndicator
                var activityIndicatorTransition = transition
                if let current = self.activityIndicator {
                    activityIndicator = current
                } else {
                    activityIndicatorTransition = .immediate
                    activityIndicator = ActivityIndicator(type: .custom(component.background.foreground, 22.0, 2.0, true))
                    activityIndicator.view.alpha = 0.0
                    self.activityIndicator = activityIndicator
                    self.containerView.addSubview(activityIndicator.view)
                }
                let indicatorSize = CGSize(width: 22.0, height: 22.0)
                transition.setAlpha(view: activityIndicator.view, alpha: 1.0)
                activityIndicatorTransition.setFrame(view: activityIndicator.view, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - indicatorSize.width) / 2.0), y: floorToScreenPixels((availableSize.height - indicatorSize.height) / 2.0)), size: indicatorSize))
            } else {
                if let activityIndicator = self.activityIndicator {
                    self.activityIndicator = nil
                    transition.setAlpha(view: activityIndicator.view, alpha: 0.0, completion: { [weak activityIndicator] _ in
                        activityIndicator?.view.removeFromSuperview()
                    })
                }
            }
            
            if component.background.isShimmering {
                let shimmeringView: ButtonShimmeringView
                var shimmeringTransition = transition
                if let current = self.shimmeringView {
                    shimmeringView = current
                } else {
                    shimmeringTransition = .immediate
                    shimmeringView = ButtonShimmeringView(frame: .zero)
                    self.shimmeringView = shimmeringView
                    self.containerView.insertSubview(shimmeringView, at: 0)
                }
                shimmeringView.update(size: availableSize, background: component.background, cornerRadius: component.background.cornerRadius, transition: shimmeringTransition)
                shimmeringTransition.setFrame(view: shimmeringView, frame: CGRect(origin: .zero, size: availableSize))
            } else if let shimmeringView = self.shimmeringView {
                self.shimmeringView = nil
                shimmeringView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { _ in
                    shimmeringView.removeFromSuperview()
                })
            }
            
            if component.background.style == .glass {
                let chromeView: UIImageView
                var chromeTransition = transition
                if let current = self.chromeView {
                    chromeView = current
                } else {
                    chromeTransition = .immediate
                    chromeView = UIImageView()
                    self.chromeView = chromeView
                    if let shimmeringView = self.shimmeringView {
                        self.containerView.insertSubview(chromeView, aboveSubview: shimmeringView)
                    } else {
                        self.containerView.insertSubview(chromeView, at: 0)
                    }
                    
                    chromeView.layer.compositingFilter = "overlayBlendMode"
                    chromeView.alpha = 0.8
                    chromeView.image = GlassBackgroundView.generateForegroundImage(size: CGSize(width: 26.0 * 2.0, height: 26.0 * 2.0), isDark: component.background.color.lightness < 0.4, fillColor: .clear)
                }
                chromeTransition.setFrame(view: chromeView, frame: CGRect(origin: .zero, size: availableSize))
            } else if let chromeView = self.chromeView {
                self.chromeView = nil
                chromeView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { _ in
                    chromeView.removeFromSuperview()
                })
            }
            
            transition.setPosition(view: self.containerView, position: CGPoint(x: availableSize.width / 2.0, y: availableSize.height / 2.0))
            transition.setBoundsSize(view: self.containerView, size: availableSize)
            
            return availableSize
        }
    }

    public func makeView() -> View {
        return View(frame: CGRect())
    }

    public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
        return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
    }
}

private class ButtonShimmeringView: UIView {
    private var shimmerView = ShimmerEffectForegroundView()
    private var borderView = UIView()
    private var borderMaskView = UIView()
    private var borderShimmerView = ShimmerEffectForegroundView()
    
    override init(frame: CGRect) {
        self.borderView.isUserInteractionEnabled = false
        
        self.borderMaskView.layer.borderWidth = 1.0 + UIScreenPixel
        self.borderMaskView.layer.borderColor = UIColor.white.cgColor
        self.borderView.mask = self.borderMaskView
        
        self.borderView.addSubview(self.borderShimmerView)
        
        super.init(frame: frame)
        
        self.isUserInteractionEnabled = false
        
        self.addSubview(self.shimmerView)
        self.addSubview(self.borderView)
    }
    
    required init?(coder: NSCoder) {
        preconditionFailure()
    }
    
    func update(size: CGSize, background: ButtonComponent.Background, cornerRadius: CGFloat, transition: ComponentTransition) {
        let color = background.foreground
        
        let alpha: CGFloat
        let borderAlpha: CGFloat
        let compositingFilter: String?
        if color.lightness > 0.5 {
            alpha = 0.5
            borderAlpha = 0.75
            compositingFilter = "overlayBlendMode"
        } else {
            alpha = 0.2
            borderAlpha = 0.3
            compositingFilter = nil
        }
        
        self.backgroundColor = background.color
        self.layer.cornerRadius = cornerRadius
        self.borderMaskView.layer.cornerRadius = cornerRadius
        
        self.shimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(alpha), gradientSize: 70.0, globalTimeOffset: false, duration: 4.0, horizontal: true)
        self.shimmerView.layer.compositingFilter = compositingFilter
        
        self.borderShimmerView.update(backgroundColor: .clear, foregroundColor: color.withAlphaComponent(borderAlpha), gradientSize: 70.0, globalTimeOffset: false, duration: 4.0, horizontal: true)
        self.borderShimmerView.layer.compositingFilter = compositingFilter
        
        let bounds = CGRect(origin: .zero, size: size)
        transition.setFrame(view: self.shimmerView, frame: bounds)
        transition.setFrame(view: self.borderView, frame: bounds)
        transition.setFrame(view: self.borderMaskView, frame: bounds)
        transition.setFrame(view: self.borderShimmerView, frame: bounds)
        
        self.shimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: size.width * 4.0, y: 0.0), size: size), within: CGSize(width: size.width * 9.0, height: size.height))
        self.borderShimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: size.width * 4.0, y: 0.0), size: size), within: CGSize(width: size.width * 9.0, height: size.height))
    }
}
